#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright (C) 1994  Ling Li
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

VALUE_STRING = 0
VALUE_INT = 1
VALUE_BOOL = 2

def get_available_methods():
    methods = ['standard']
    try:
        import gconf
        methods.append('gconf')
    except ImportError:
        pass
    return methods

def get_config(method, *args):
    if method == 'gconf':
        return GConfConfig(*args)
    elif method == 'standard':
        return StandardConfig(*args)

def create_standard_config_from_schema_file(config_path, schema_path, prefix):
    def get_text(node):
        for cn in node.childNodes:
            if cn.nodeType == cn.TEXT_NODE: return cn.data
        return None

    import ConfigParser
    new_config = ConfigParser.SafeConfigParser()

    from xml.dom import minidom
    dom = minidom.parse(schema_path)
    assert dom.documentElement.tagName == 'gconfschemafile'
    for node in dom.getElementsByTagName('schema'):
        applyto = get_text(node.getElementsByTagName('applyto')[0])
        section = applyto[len(prefix)+1:]
        section, keyname = section.split('/')
        value = get_text(node.getElementsByTagName('default')[0])
        if not new_config.has_section(section):
            new_config.add_section(section)
        new_config.set(section, keyname, value)

    new_config.write(file(config_path, 'w'))
    return

def create_standard_from_gconf(schema_path, config_path, gconf_config):
    def get_text(node):
        for cn in node.childNodes:
            if cn.nodeType == cn.TEXT_NODE: return cn.data
        return None

    standard_config = StandardConfig(config_path)
    prefix = gconf_config.prefix
    from xml.dom import minidom
    dom = minidom.parse(schema_path)
    assert dom.documentElement.tagName == 'gconfschemafile'
    for node in dom.getElementsByTagName('schema'):
        applyto = get_text(node.getElementsByTagName('applyto')[0])
        section = applyto[len(prefix)+1:]
        section, option = section.split('/')
        type = get_text(node.getElementsByTagName('type')[0])
        if type == 'string':
            value = gconf_config.get_string(section, option)
            standard_config.set_string(section, option, value)
        elif type == 'int':
            value = gconf_config.get_int(section, option)
            standard_config.set_int(section, option, value)
        elif type == 'bool':
            value = gconf_config.get_bool(section, option)
            standard_config.set_bool(section, option, value)
    return standard_config

def create_gconf_from_standard(schema_path, prefix, standard_config):
    def get_text(node):
        for cn in node.childNodes:
            if cn.nodeType == cn.TEXT_NODE: return cn.data
        return None

    gconf_config = GConfConfig(prefix)
    from xml.dom import minidom
    dom = minidom.parse(schema_path)
    assert dom.documentElement.tagName == 'gconfschemafile'
    for node in dom.getElementsByTagName('schema'):
        applyto = get_text(node.getElementsByTagName('applyto')[0])
        section = applyto[len(prefix)+1:]
        section, option = section.split('/')
        type = get_text(node.getElementsByTagName('type')[0])
        if type == 'string':
            value = standard_config.get_string(section, option)
            gconf_config.set_string(section, option, value)
        elif type == 'int':
            value = standard_config.get_int(section, option)
            gconf_config.set_int(section, option, value)
        elif type == 'bool':
            value = standard_config.get_bool(section, option)
            gconf_config.set_bool(section, option, value)
    return gconf_config

class StandardConfig:

    __registry = {}
    __registry_id = 0
    __index = {}
    
    __save_timer = None

    def __init__(self, path): 
        import ConfigParser
        self.__path = path
        self.__config = ConfigParser.SafeConfigParser()
        self.__config.read(self.__path)
        return

    def __getattr__(self, name):
        if name == 'name': return 'standard'
        raise AttributeError, name

    def __notify(self, section, keyname):
        from gtk import idle_add
        class Value:
            def __init__(self, config, section, keyname):
                self.__config = config
                self.__section = section
                self.__keyname = keyname
            def get_string(self):
                return self.__config.get_string(self.__section, self.__keyname)
            def get_int(self):
                return self.__config.get_int(self.__section, self.__keyname)
            def get_bool(self):
                return self.__config.get_bool(self.__section, self.__keyname)
        if not self.__index.has_key((section, keyname)): return
        for id in self.__index[(section, keyname)]:
            try:
                func, args = self.__registry[id]
            except KeyError:
                continue
            value = Value(self, section, keyname)
            idle_add(func, self, id, value, *args)
        return

    def notify_add(self, section, keyname, func, *args):
        id = self.__registry_id
        self.__registry_id = self.__registry_id + 1
        self.__registry[id] = (func, args)
        if self.__index.has_key((section, keyname)):
            self.__index[(section, keyname)].append(id)
        else:
            self.__index[(section, keyname)] = [id]
        return id

    def notify_remove(self, id):
        del(self.__registry[id])
        for v in self.__index.values():
            v.remove(id)
        return

    def delete(self):
        from os import remove
        remove(self.__path)
        return

    def save(self):
        if self.__save_timer == None:
            import threading
            self.__save_timer = threading.Timer(1, self.__true_save)
            self.__save_timer.start()
        return

    def __true_save(self):
        self.__config.write(file(self.__path, 'w'))
        return

    def sections(self):
        return self.__config.sections()

    def options(self, section):
        return self.__config.options(section)

    def get_string(self, section, keyname):
        return self.__config.get(section, keyname)

    def get_bool(self, section, keyname):
        return self.__config.getboolean(section, keyname)

    def get_int(self, section, keyname):
        return self.__config.getint(section, keyname)

    def set_string(self, section, keyname, value):
        if not self.__config.has_section(section):
            self.__config.add_section(section)
        self.__config.set(section, keyname, value)
        self.__notify(section, keyname)
        self.save()
        return

    def set_int(self, section, keyname, value):
        if not self.__config.has_section(section):
            self.__config.add_section(section)
        self.__config.set(section, keyname, value)
        self.__notify(section, keyname)
        self.save()
        return

    def set_bool(self, section, keyname, value):
        if not self.__config.has_section(section):
            self.__config.add_section(section)
        self.__config.set(section, keyname, value)
        self.__notify(section, keyname)
        self.save()
        return

class GConfConfig:

    __registry = {}
    __index = {}

    def __init__(self, prefix): 
        import gconf
        self.__prefix = prefix
        self.__config = gconf.client_get_default()
        self.__config.add_dir(self.__prefix, gconf.CLIENT_PRELOAD_NONE)
        return

    def __del__(self):
        self.__config.remove_dir(self.__prefix)
        return

    def __getattr__(self, name):
        if name == 'name': return 'gconf'
        elif name == 'prefix': return self.__prefix
        raise AttributeError, name

    def notify_add(self, section, keyname, func, *args):
        def custom_func(config, id, entry, args):
            return args[0](config, id, entry.value, *args[1:])
        key = '%s/%s/%s' % (self.__prefix, section, keyname)
        a = [func]
        a.extend(args)
        return self.__config.notify_add(key, custom_func, a)

    def notify_remove(self, id):
        return self.__config.notify_remove(id)

    def delete(self):
        return

    def save(self):
        return

    def sections(self):
        sections = []
        for path in self.__config.all_dirs(self.__prefix):
            sections.append(path[len(self.__prefix)+1:])
        return sections

    def options(self, section):
        options = []
        section = '%s/%s' % (self.__prefix, section)
        for entry in self.__config.all_entries(section):
            print entry.key
            options.append(entry.key[len(section) + 1:])
        return options

    def get_string(self, section, keyname):
        key = '%s/%s/%s' % (self.__prefix, section, keyname)
        return self.__config.get_string(key)

    def get_bool(self, section, keyname):
        key = '%s/%s/%s' % (self.__prefix, section, keyname)
        return self.__config.get_bool(key)

    def get_int(self, section, keyname):
        key = '%s/%s/%s' % (self.__prefix, section, keyname)
        return self.__config.get_int(key)
        
    def set_string(self, section, keyname, value):
        key = '%s/%s/%s' % (self.__prefix, section, keyname)
        self.__config.set_string(key, value)
        return

    def set_int(self, section, keyname, value):
        key = '%s/%s/%s' % (self.__prefix, section, keyname)
        self.__config.set_int(key, value)
        return

    def set_bool(self, section, keyname, value):
        key = '%s/%s/%s' % (self.__prefix, section, keyname)
        self.__config.set_bool(key, value)
        return
